import { Injectable } from '@nestjs/common'
import { UserService } from 'src/user/user.service'
import { UserEntity } from 'src/user/entities/user.entity'
import { JwtService } from '@nestjs/jwt'
import { RedisService } from 'src/redis/redis.service'
import { MenuService } from 'src/menu/menu.service';
import { RoleService } from 'src/role/role.service';

@Injectable()
export class AuthService {
  constructor(
    private userService: UserService,
    private menuService: MenuService,
    private roleService: RoleService,
    private jwtService: JwtService,
    private redisService: RedisService
  ) { }

  async validateUser(username: string, password: string): Promise<UserEntity | null> {
    const user = await this.userService.findOne(username)
    if (!user) return null
    return user
  }

  private async createToken(playload: Partial<UserEntity>) {
    let token = await this.jwtService.sign(playload, { expiresIn: 10800 })
    return token
  }

  private async createRefreshToken(playload) {
    let refreshToken = await this.jwtService.sign(playload, { expiresIn: 43200 })
    return refreshToken
  }

  //获取角色的权限
  private async getRoleMenus(user: any) {
    let roles = user.role
    let menuList = []
    for (const role of roles) {
      //获取用户的权限
      let roleAuth = await this.roleService.getRoleMenus(role.id);
      menuList = menuList.concat(roleAuth)
    };
    return menuList
  }

  async login(user: any, type = 'login') {
    let state = await this.redisService.get(`user:${user.id}`);
    if (state !== null && state !== undefined && +state == 0) {
      let second = await this.redisService.getKeyTTL(`user:${user.id}`);
      let time = second > 0 ? `您将于${second}秒后解封` : '永久封禁'
      throw new Error(time)
    }
    // 创建token
    let token = await this.createToken({
      id: user.id,
      username: user.username,
    })
    let refreshToken = await this.createRefreshToken({ id: user.id })
    this.redisService.set(`user:${user.id}`, token)
    this.redisService.set(`user:${user.id}:refreshToken`, refreshToken, 12 * 60 * 60)
    this.redisService.setHashData(`user:${user.id}:userInfo`, {
      id: user.id,
      username: user.username,
    })
    // 每个用户应该只能使用refresh_token 刷新access_token 3次，3次之后就要用户登录
    if (type === 'replay') {
      this.redisService.incr(`user:${user.id}:count`);
      if (+this.redisService.get(`user:${user.id}:count`) > 3) {
        this.redisService.del(`user:${user.id}:refreshToken`)
      }
    }
    return { access_token: token, refresh_token: refreshToken }
  }

  async getUserInfoFn(user: any) {
    let userAuthList = [], result = [];
    // 获取用户所有权限，admin拥有所有的权限
    if (user.role.length && user.role.findIndex(role => role.name === 'admin') >= 0) {
      result = await this.menuService.findAll()
    } else {
      //角色权限
      let roleMenus = await this.getRoleMenus(user)
      //获取用户的权限
      let userAuth = await this.userService.getUserMenus(user.id);
      userAuthList = userAuthList.concat(roleMenus, userAuth);
      //去除重复的权限
      //一种思路，但是对于菜单来说，可能无法判断子路由
      // let ids = new Set(arrayWithDuplicateObjects.map(item => item.id));
      // let uniqueObjects = arrayWithDuplicateObjects.filter(item => ids.has(item.id));
      result = Array.from(new Set(userAuthList.map(menu => JSON.stringify(menu))))
        .map(item => JSON.parse(item))
    }
    return { userInfo: user, userAuthList: result, }
  }

  async getUser(user: UserEntity) {
    return await this.userService.findOneById(user.id)
  }
}
